#include "CD3D11Sprite.h"

#include "Render\CMesh.h"
#include "Render\CTexture.h"
#include "CD3D11RenderSystem.h"

namespace Nervus {
	namespace Render {
		//----------------------------------------------------------------------------------
		D3D11Sprite::D3D11Sprite(D3D11RenderSystem* renderer, D3DXVECTOR2 pos, Texture* tex){
			mRenderSystem = renderer;
			mTextureFile = tex;
			mPosX = pos.x;
			mPosY = pos.y;
			mWidth = tex->mImageWidth;
			mHeight = tex->mImageHeight;
		}
		//----------------------------------------------------------------------------------
		D3D11Sprite::~D3D11Sprite(){

		}
		//----------------------------------------------------------------------------------
		bool D3D11Sprite::loadSprite(){
			//In D3D11 (0;0) is at left-bottom corner
			//Pos points at left-top corner
			//mVertices.push_back({ (f32)mPosX, (f32)mPosY - mHeight, 10.0f, 0xFFFFFFFF, 1.0f, 1.0f });
			//mVertices.push_back({ (f32)mPosX + mWidth, (f32)mPosY - mHeight, 10.0f, 0xFFFFFFFF, 0.0f, 1.0f });
			//mVertices.push_back({ (f32)mPosX, (f32)mPosY, 10.0f, 0xFFFFFFFF, 1.0f, 0.0f });
			//mVertices.push_back({ (f32)mPosX + mWidth, (f32)mPosY, 10.0f, 0xFFFFFFFF, 0.0f, 0.0f });

			mVertices.push_back({ (f32)mPosX + mWidth, (f32) mRenderSystem->mBufferHeight - (mPosY + mHeight),
				10.0f, 0xFFFFFFFF, 1.0f, 1.0f });
			mVertices.push_back({ (f32)mPosX, (f32)mRenderSystem->mBufferHeight - (mPosY + mHeight),
				10.0f, 0xFFFFFFFF, 0.0f, 1.0f });
			mVertices.push_back({ (f32)mPosX + mWidth, (f32)mRenderSystem->mBufferHeight - mPosY,
				10.0f, 0xFFFFFFFF, 1.0f, 0.0f });
			mVertices.push_back({ (f32)mPosX, (f32)mRenderSystem->mBufferHeight - mPosY,
				10.0f, 0xFFFFFFFF, 0.0f, 0.0f });


			D3D11_BUFFER_DESC bd;
			ZeroMemory(&bd, sizeof(bd));

			bd.Usage = D3D11_USAGE_DYNAMIC;
			bd.ByteWidth = sizeof(MeshVertex)* mVertices.size();
			bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
			bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

			mRenderSystem->mDevice->CreateBuffer(&bd, NULL, &mVertexBuffer);


			D3D11_MAPPED_SUBRESOURCE ms;
			mRenderSystem->mDeviceContext->Map(mVertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
			memcpy(ms.pData, &(mVertices[0]), sizeof(MeshVertex)* mVertices.size());
			mRenderSystem->mDeviceContext->Unmap(mVertexBuffer, NULL);



			DWORD* indices = new DWORD[mVertices.size()];
			for (u32 i = 0; i < mVertices.size(); i++){
				indices[i] = i;
			}


			D3D11_BUFFER_DESC indexBufferDesc;
			ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));

			indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
			indexBufferDesc.ByteWidth = sizeof(DWORD)* 2 * mVertices.size();
			indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
			indexBufferDesc.CPUAccessFlags = 0;
			indexBufferDesc.MiscFlags = 0;


			D3D11_SUBRESOURCE_DATA iinitData;

			iinitData.pSysMem = indices;
			mRenderSystem->mDevice->CreateBuffer(&indexBufferDesc, &iinitData, &mIndexBuffer);





			Texture* tex = mTextureFile;



			u32 imageSize = tex->mImageHeight * tex->mImageWidth * 4;
			u8* revData = new u8[imageSize];



			for (i32 c = tex->mImageHeight - 1; c >= 0; c--){	//Processes rows
				for (u32 r = 0; r < tex->mImageWidth; r++){		//Processes one row
					/*
					D3D11 has color format RGBA, while Texture stores as ARGB
					Moreover, DirectX reads texture data from the end, so it needs to be reversed
					*/
					revData[c*tex->mImageWidth * 4 + r * 4 + 3] =
						tex->mImageData[(tex->mImageHeight - c - 1)*tex->mImageWidth * 4 + r * 4];
					revData[c*tex->mImageWidth * 4 + r * 4] =
						tex->mImageData[(tex->mImageHeight - c - 1)*tex->mImageWidth * 4 + r * 4 + 1];
					revData[c*tex->mImageWidth * 4 + r * 4 + 1] =
						tex->mImageData[(tex->mImageHeight - c - 1)*tex->mImageWidth * 4 + r * 4 + 2];
					revData[c*tex->mImageWidth * 4 + r * 4 + 2] =
						tex->mImageData[(tex->mImageHeight - c - 1)*tex->mImageWidth * 4 + r * 4 + 3];
				}
			}







			D3D11_SUBRESOURCE_DATA sd;
			ZeroMemory(&sd, sizeof(sd));
			sd.pSysMem = revData;
			sd.SysMemPitch = tex->mImageWidth * 4;	//Bytes between each new row

			D3D11_TEXTURE2D_DESC td;
			ZeroMemory(&td, sizeof(td));

			td.Width = tex->mImageWidth;
			td.Height = tex->mImageHeight;
			td.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			td.MipLevels = td.ArraySize = 1;
			td.SampleDesc.Count = 1;
			td.Usage = D3D11_USAGE_DEFAULT;
			td.BindFlags = D3D11_BIND_SHADER_RESOURCE;




			mRenderSystem->mDevice->CreateTexture2D(&td, &sd, &mTexture);


			/*
			D3D11_MAPPED_SUBRESOURCE ms2;
			mRenderSystem->mDeviceContext->Map(mVertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms2);
			memcpy(ms2.pData, tex->mImageData, tex->mImageWidth*tex->mImageHeight*4);
			mRenderSystem->mDeviceContext->Unmap(mVertexBuffer, NULL);
			*/



			mRenderSystem->mDevice->CreateShaderResourceView(mTexture, nullptr, &mTextureView);



			// Describe the Sample State
			D3D11_SAMPLER_DESC sampDesc;
			ZeroMemory(&sampDesc, sizeof(sampDesc));
			sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
			sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
			sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
			sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
			sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
			sampDesc.MinLOD = 0;
			sampDesc.MaxLOD = D3D11_FLOAT32_MAX;

			//Create the Sample State
			mRenderSystem->mDevice->CreateSamplerState(&sampDesc, &mTexSamplerState);





			return true;
		}
		//----------------------------------------------------------------------------------
		void D3D11Sprite::renderSprite(){
			mRenderSystem->enable2D();
			UINT stride = sizeof(MeshVertex);
			UINT offset = 0;
			mRenderSystem->mDeviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &offset);
			mRenderSystem->mDeviceContext->IASetIndexBuffer(mIndexBuffer, DXGI_FORMAT_R32_UINT, 0);


			mRenderSystem->mDeviceContext->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

			mRenderSystem->mDeviceContext->PSSetShaderResources(0, 1, &mTextureView);
			mRenderSystem->mDeviceContext->PSSetSamplers(0, 1, &mTexSamplerState);



			mRenderSystem->mDeviceContext->DrawIndexed(mVertices.size(), 0, 0);
		}
		//----------------------------------------------------------------------------------
	}
}